package nio.groupchat;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

/**
 * NIO 网络编程应用实例-群聊系统
 * 服务端
 *
 * @author chenyuan
 * @date 2020/11/4 14:38
 */
public class Server {
	// 定义属性
	private Selector selector;
	private ServerSocketChannel listenerChannell;
	private static final int PORT = 6666;

	// 构造器
	public Server() {
		try {
			// 得到选择器
			selector = Selector.open();
			// 得到 ServerSocketChannel
			listenerChannell = ServerSocketChannel.open();
			// 绑定端口
			listenerChannell.socket().bind(new InetSocketAddress(PORT));
			// 设置非阻塞
			listenerChannell.configureBlocking(false);
			// 把 listenerChannell 注册到 Selector 中，关注连接事件
			listenerChannell.register(selector, SelectionKey.OP_ACCEPT);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {

		}
	}

	// 监听，处理客户端的连接事件
	public void listen() {
		try {
			// 循环处理
			while (true) {
				int select = selector.select();
				if (select > 0) { // 表示有事件要处理

					// 遍历得到 SelectionKey 集合
					Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
					while (iterator.hasNext()) {
						// 取出 SelectionKey
						SelectionKey key = iterator.next();

						//处理连接事件
						if (key.isAcceptable()) {
							// 通过 ServerSocketChannel 获得 socketChannel
							SocketChannel socketChannel = listenerChannell.accept();
							// 设置非阻塞
							socketChannel.configureBlocking(false);
							// 将 socketChannel 注册到 Selector
							socketChannel.register(selector, SelectionKey.OP_READ);
							// 给出提示
							System.out.println(socketChannel.getRemoteAddress() + "上线了~");
						}

						// 处理读事件
						if (key.isReadable()) {
							// 处理读的方法
							read(key);
						}

						iterator.remove();

					}

				} else {
					System.out.println("等待中……");
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {

		}
	}

	// 读取客户端消息
	public void read(SelectionKey key) {
		// 定义一个 SocketChannel
		SocketChannel socketChannel = null;
		try {
			// 得到关联的 Channel
			socketChannel = (SocketChannel) key.channel();
			// 创建 ByteBuffer
			ByteBuffer buffer = ByteBuffer.allocate(1024);
			// 将 socketChannel 的数据读到 Buffer
			int read = socketChannel.read(buffer);
			// 根据 read 的值，做出对应的处理
			if (read > 0) {
				// 读取到了数据
				String s = new String(buffer.array());
				System.out.println("【服务端】收到客户端消息：" + s);
				// 向其他客户端转发消息,需要排除自己
				sendMessageToOther(s, socketChannel);
			}
		} catch (IOException e) {
			// 如果在读取数据时， 发生异常，则表示离线了
			try {
				System.out.println(socketChannel.getRemoteAddress() + "离线了~");
				// 取消注册
				key.channel();
				// 关闭通道
				socketChannel.close();
			} catch (IOException ioException) {
				ioException.printStackTrace();
			}
		}
	}

	// 转发消息给其他客户端
	public void sendMessageToOther(String message, SocketChannel selfChannel) throws IOException {
		System.out.println("服务器转发消息中……");
		// 遍历所有注册到 Selector 上的 socketChannel ，并排除自己
		for (SelectionKey key : selector.keys()) {
			// 通过 key 取出对应的 SocketChannel
			Channel channel = key.channel();
			// 排除自己, channel 必须是一个 SocketChannel 类型的 并且 channel 不等于自己
			if (channel instanceof SocketChannel && channel != selfChannel) {
				// 转换 Channel 类型
				SocketChannel dest = (SocketChannel) channel;
				// 将 message 存储到 Buffer
				ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
				// 将 Buffer 的数据写入通道
				dest.write(buffer);
			}
		}
	}


	public static void main(String[] args) {
		// 创建一个服务器对象
		Server server = new Server();
		server.listen();
	}
}
